package kubernetescli

import (
	"context"
	"errors"
	"strconv"
	"time"

	"github.com/Kindling-project/chaos-backend/api"
	"github.com/Kindling-project/chaos-backend/tools/wrapper"
	"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
)

type iochaos struct {
}

func (n *iochaos) ToChaosVO(obj *interface{}) []api.Chaos {
	return wrapper.IOChaosToChaosVO(obj)
}

func (n *iochaos) List() (interface{}, error) {
	if client == nil {
		return nil, errors.New("kube-client not initialized yet")
	}
	result := v1alpha1.IOChaosList{}
	err := client.
		Get().
		Resource("iochaos").
		Namespace("train-ticket").
		Do(context.Background()).
		Into(&result)
	return result, err
}

func (n *iochaos) Create(vo *api.Chaos) (interface{}, error) {
	if client == nil {
		return nil, errors.New("kube-client not initialized yet")
	}

	n.DeleteAll()

	iochaos := buildIOChaos(vo, defaultIOChaosParam)
	result := v1alpha1.IOChaos{}
	err := client.
		Post().
		Namespace(iochaos.Namespace).
		Resource("iochaos").
		Body(iochaos).
		Do(context.Background()).
		Into(&result)
	return result, err
}

func (n *iochaos) DeleteAll() (interface{}, error) {
	if client == nil {
		return nil, errors.New("kube-client not initialized yet")
	}

	result := v1alpha1.IOChaosList{}
	err := client.
		Get().
		Resource("iochaos").
		Namespace("train-ticket").
		Do(context.Background()).
		Into(&result)

	if err != nil {
		return nil, err
	}

	var lastChaos v1alpha1.IOChaos
	for _, chaos := range result.Items {
		if v, ok := chaos.Labels["kindling-chaos"]; ok && v == "train-ticket" {
			result := v1alpha1.IOChaos{}
			err := client.
				Delete().
				Resource("iochaos").
				Name(chaos.Name).
				Namespace(chaos.Namespace).
				Do(context.Background()).Into(&result)
			if err != nil {
				return nil, err
			}
			lastChaos = chaos
		}
	}

	return lastChaos, err
}

var defaultIOChaosParam = v1alpha1.IOChaos{
	Spec: v1alpha1.IOChaosSpec{
		Action:     "latency",
		Delay:      "200ms",
		VolumePath: "/io-logs",
		Percent:    100,
		Methods:    []v1alpha1.IoMethod{v1alpha1.Read, v1alpha1.Write},
	},
}

func buildIOChaos(vo *api.Chaos, params v1alpha1.IOChaos) *v1alpha1.IOChaos {
	var resource = params.DeepCopy()
	ts := time.Now().Unix()

	resource.Name = "iochaos" + "-" + strconv.FormatInt(ts, 10)
	resource.Namespace = "train-ticket"
	// Mark labels
	resource.Labels = map[string]string{
		"kindling-chaos": "train-ticket",
	}
	resource.Annotations = map[string]string{
		"describe":       vo.Desc,
		"complex-action": vo.ComplexAction,
	}
	resource.Spec.Action = v1alpha1.IOChaosType(vo.ChaosAction)

	for i := 0; i < len(vo.Params); i++ {
		switch vo.Params[i].Name {
		case "instance":
			resource.Spec.Selector.LabelSelectors = map[string]string{
				"app": vo.Params[i].Value,
			}
			resource.Annotations["target"] = vo.Params[i].Value
			resource.Spec.Mode = v1alpha1.AllMode
		}
	}

	return resource
}
